package com.self.springframework.beans.factory.xml;

import cn.hutool.core.util.StrUtil;
import com.self.springframework.beans.PropertyValue;
import com.self.springframework.beans.factory.config.BeanDefinition;
import com.self.springframework.beans.factory.config.BeanReference;
import com.self.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
    @Override
    public void registerBeanDefinitions(Document document, BeanDefinitionRegistry registry) {
        this.doRegisterBeanDefinitions(document.getDocumentElement(),registry);
    }

    private void doRegisterBeanDefinitions(Element root,BeanDefinitionRegistry registry) {
        // 如果配置了配置了屬性:配置文件,根据配置文件属性进行隔离
        String profileSpec = root.getAttribute("profile");
        if (StrUtil.isNotEmpty(profileSpec)) {
            // TODO:待添加通过environment对象匹配激活的属性文件
        }
        // 解析前处理,留给子类实现
        this.preProcessXml(root);
        this.parseBeanDefinitions(root,registry);
        // 解析后处理,留给子类实现
        this.postProcessXml(root);
    }

    protected void parseBeanDefinitions(Element root,BeanDefinitionRegistry registry/*, BeanDefinitionParserDelegate delegate*/) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                // TODO:待添加针对默认标签的解析
//                if (delegate.isDefaultNamespace(ele)) {
                this.parseDefaultElement(ele,registry/*, delegate*/);
//                }
                // TODO:待添加针对自定义标签的解析
//                else {
//                    delegate.parseCustomElement(ele);
//                }
            }
        }
    }

    private void parseDefaultElement(Element ele,BeanDefinitionRegistry registry) {
        // 对import标签进行处理
        if (ele.getTagName().equals("import")) {
//            this.importBeanDefinitionResource(ele);
        }
        // 对alias标签进行处理
        else if (ele.getTagName().equals("alias")) {
//            this.processAliasRegistration(ele);
        }
        // 对bean标签进行处理
        else if (ele.getTagName().equals("bean")) {
            this.processBeanDefinition(ele,registry);
        }
        // 对beans标签进行处理
        else if (ele.getTagName().equals("beans")) {
            this.doRegisterBeanDefinitions(ele,registry);
        }
    }

    protected void processBeanDefinition(Element ele,BeanDefinitionRegistry registry) {

        try {
            // 解析标签
            String id = ele.getAttribute("id");
            String className = ele.getAttribute("class");
            String name = ele.getAttribute("name");
            String initMethod = ele.getAttribute("init-method");
            String destroyMethodName = ele.getAttribute("destroy-method");
            String scope = ele.getAttribute("scope");

            // 获取Class
            Class<?> clazz = Class.forName(className);
            // 设置优先级 id>name
            String beanName = (null != id && !"".equals(id)) ? id : name;
            if (StrUtil.isEmpty(beanName)) {
                beanName = StrUtil.lowerFirst(clazz.getSimpleName());
            }
            // 定义bean
            BeanDefinition beanDefinition = new BeanDefinition(clazz);
            beanDefinition.setInitMethodName(initMethod);
            beanDefinition.setDestroyMethodName(destroyMethodName);

            if (StrUtil.isNotEmpty(scope)) {
                beanDefinition.setScope(scope);
            }

            // 读取属性填充
            NodeList nodeList = ele.getChildNodes();
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                if (Element.ELEMENT_NODE == node.getNodeType()) {
                    Element element = (Element) node;
                    if (element.getTagName().equals("property")) {
                        String attrName = element.getAttribute("name");
                        String attrValue = element.getAttribute("value");
                        String attrRef = element.getAttribute("ref");
                        Object value = (attrValue != null && !"".equals(attrValue)) ? attrValue : new BeanReference(attrRef);
                        PropertyValue propertyValue = new PropertyValue(attrName, value);
                        beanDefinition.getPropertyValues().setPropertyValue(propertyValue);
                    }
                }
            }

        // 注册beanDefinition
        registry.registerBeanDefinition(beanName, beanDefinition);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    protected void postProcessXml(Element root) {
    }

    protected void preProcessXml(Element root) {
    }
}
